package com.zhanghe.im.protocol.command;

import com.zhanghe.im.request.*;
import com.zhanghe.im.response.*;
import com.zhanghe.im.serializer.KyroSerializer;
import com.zhanghe.im.serializer.Serializer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;

import java.util.HashMap;
import java.util.Map;

public class PacketCodeC {

    public static PacketCodeC INSTANCE = new PacketCodeC();

    public static final int MAGIC_NUM = 0xab1234;

    private final Map<Byte,Class<? extends Packet>> packetTypeMap;

    private final Map<Byte,Serializer> serializerMap;

    private PacketCodeC(){
        packetTypeMap = new HashMap<>();

        packetTypeMap.put(Command.LOGIN_REQUEST,LoginRequestPacket.class);
        packetTypeMap.put(Command.LOGIN_RESPONSE,LoginResponsePacket.class);
        packetTypeMap.put(Command.MESSAGE_REQUEST,MessageRequestPacket.class);
        packetTypeMap.put(Command.MESSAGE_RESPONSE,MessageResponsePacket.class);
        packetTypeMap.put(Command.CREATE_GROUP_REQUEST,CreateGroupRequestPacket.class);
        packetTypeMap.put(Command.CREATE_GROUP_RESPONSE,CreateGroupResPonsePacket.class);
        packetTypeMap.put(Command.JOIN_GROUP_REQUEST,JoinGroupRequestPacket.class);
        packetTypeMap.put(Command.JOIN_GROUP_RESPONSE,JoinGroupResponsePacket.class);
        packetTypeMap.put(Command.QUIT_GROUP_REQUEST,QuitGroupRequestPacket.class);
        packetTypeMap.put(Command.QUIT_GROUP_RESPONSE,QuitGroupResponsePacket.class);
        packetTypeMap.put(Command.LIST_GROUP_MEMBER_REQUEST,ListGroupMemberRequestPacket.class);
        packetTypeMap.put(Command.LIST_GROUP_MEMBER_RESPONSE,ListGroupMemberResponsePacket.class);
        packetTypeMap.put(Command.HEART_BEAT_REQUEST,HeartBeatRequestPacket.class);
        packetTypeMap.put(Command.HEART_BEAT_RESPONSE,HeartBeatResponsePacket.class);

        KyroSerializer kyroSerializer = new KyroSerializer();
        serializerMap = new HashMap<>();
        serializerMap.put(kyroSerializer.getSerializerAlgorithm(),kyroSerializer);
    }

    public ByteBuf encode(Packet packet){
        //创建ByteBuf对象
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.ioBuffer();
        //序列化packet对象
        byte[] bytes = Serializer.DEFAULT.serialize(packet);
        //进行编码
        byteBuf.writeInt(MAGIC_NUM);
        byteBuf.writeByte(packet.getVersion());
        byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlgorithm());
        byteBuf.writeByte(packet.getCommand());
        byteBuf.writeInt(bytes.length);
        byteBuf.writeBytes(bytes);

        return byteBuf;
    }

    public void encode(ByteBuf byteBuf,Packet packet){
        //序列化packet对象
        byte[] bytes = Serializer.DEFAULT.serialize(packet);
        //进行编码
        byteBuf.writeInt(MAGIC_NUM);
        byteBuf.writeByte(packet.getVersion());
        byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlgorithm());
        byteBuf.writeByte(packet.getCommand());
        byteBuf.writeInt(bytes.length);
        byteBuf.writeBytes(bytes);
    }

    public Packet decode(ByteBuf byteBuf){
        // 跳过 magic number
        byteBuf.skipBytes(4);
        // 跳过版本号
        byteBuf.skipBytes(1);
        // 序列化算法标识
        byte serializeAlgorithm = byteBuf.readByte();
        // 指令
        byte command = byteBuf.readByte();
        // 数据包长度
        int length = byteBuf.readInt();
        byte[] bytes = new byte[length];
        byteBuf.readBytes(bytes);
        Class<? extends Packet> requestType = getRequestType(command);
        Serializer serializer = getSerializer(serializeAlgorithm);

        if (requestType != null && serializer != null) {
            return serializer.deserialize(requestType, bytes);
        }
        return null;
    }

    public  Class<? extends Packet> getRequestType(byte command){
        return packetTypeMap.get(command);
    }

    public Serializer getSerializer(byte serializeAlgorithm){
        return serializerMap.get(serializeAlgorithm);
    }
}
